use std::fs;

use chrono::Local;
use csv::Writer;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use tokio::task::JoinHandle;

// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[derive(Serialize, Deserialize, Debug)]
struct Manager {
    name: String,
    avatar: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Player {
    id: i32,
    name: String,
    avatar: String,
    mobile: Option<String>,
    gender: Option<i32>,
    height: Option<i32>,
    weight: Option<i32>,
    clothing_size: Option<String>,
    profession_name: Option<String>,
    residential_addr: Option<String>,
    personal_intro: Option<String>,
    birthday: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Register {
    season_id: i32,
    // 门派名称
    sect_name: String,
    // LOGO
    logo: String,
    // 状态
    status: i32,
    // 掌门
    chief: Manager,
    // 教练
    coach: Manager,
    // 领队
    leader: Manager,
    // 预估投食量
    estimate: String,
    // 赛区 ID
    zone_id: String,
    // 选手
    players: Vec<Player>,
}

#[tauri::command(rename_all = "snake_case")]
async fn export_data(target_dir: &str, data: &str) -> Result<String, ()> {
    let now = Local::now();
    let parent_dir = format!("{}/华山数据导出{}", target_dir, now.format("%Y%m%d%H%M%S"));
    println!("目录名称 {}", parent_dir);
    fs::create_dir_all(&parent_dir).expect("创建导出文件夹失败");

    let registers: Vec<Register> = serde_json::from_str(data).unwrap();
    write_csv_file(format!("{}/players.csv", &parent_dir), &registers);

    dl_images(&parent_dir, &registers).await;
    println!("下载完成");
    return Ok(String::from("Hello"));
}

async fn dl_images(dest_dir: &str, registers: &Vec<Register>) {
    // 下载图片
    let mut tasks: Vec<JoinHandle<()>> = vec![];
    let client = Client::new();
    let dest_dir = dest_dir.to_string();
    for reg in registers.into_iter() {
        let sect_name = reg.sect_name.to_string();
        let s_name = sect_name.clone();
        let logo_url = reg.logo.to_string();
        let dr = dest_dir.clone();

        let _c = client.clone();
        let t = tokio::spawn(async move {
            let p_dir = format!("{}/logo", dr);
            fs::create_dir_all(p_dir.clone()).unwrap();

            let file_name = format!("{}/{}.png", p_dir, s_name);
            dl_image(logo_url.as_str(), &file_name, &_c).await;
        });

        tasks.push(t);

        for player in reg.players.iter() {
            let s_name = sect_name.clone();
            let player_name = player.name.to_string();
            let avatar_url = player.avatar.to_string();
            let dr = dest_dir.clone();

            let _c = client.clone();

            let t = tokio::spawn(async move {
                let p_dir = format!("{}/avatars/{}", dr, s_name);
                fs::create_dir_all(p_dir.clone()).unwrap();

                let file_name = format!("{}/{}.png", p_dir, player_name);
                dl_image(avatar_url.as_str(), &file_name, &_c).await;
            });
            tasks.push(t);
        }
    }

    for ele in tasks {
        ele.await.unwrap();
    }
}

fn write_csv_file(file_name: String, registers: &Vec<Register>) {
    let mut wtr = Writer::from_path(file_name).expect("创建 CSV 文件失败");
    wtr.write_record(&[
        "门派",
        "掌门",
        "教练",
        "领队",
        "UID",
        "选手",
        "手机",
        "身高",
        "体重",
        "衣服尺寸",
        "状态",
        "赛季",
        "赛区",
    ])
    .unwrap();

    for (_, reg) in registers.iter().enumerate() {
        for (_, player) in reg.players.iter().enumerate() {
            let sect_name = reg.sect_name.clone();
            let chief_name = reg.chief.name.clone();
            let coach_name = reg.coach.name.clone();
            let leader_name = reg.leader.name.clone();
            let uid = player.id.to_string();
            let player_name = player.name.clone();
            let mobile = player.mobile.clone().unwrap_or_default();
            let height = player
                .height
                .clone()
                .map(|a| a.to_string())
                .unwrap_or_default();
            let weight = player
                .weight
                .clone()
                .map(|a| a.to_string())
                .unwrap_or_default();
            let clothing_size = player.clothing_size.clone().unwrap_or_default();
            let status = reg.status.to_string();
            let season = reg.season_id.to_string();
            let zone_id = reg.zone_id.clone();

            wtr.write_record(&[
                sect_name,
                chief_name,
                coach_name,
                leader_name,
                uid,
                player_name,
                mobile,
                height,
                weight,
                clothing_size,
                status,
                season,
                zone_id,
            ])
            .unwrap();
        }
    }

    wtr.flush().expect("写入文件出现未知错误")
}

async fn dl_image(url: &str, dest_file: &str, client: &Client) {
    match client.get(url).send().await {
        Ok(resp) => match resp.bytes().await {
            Ok(bytes) => {
                fs::write(dest_file, bytes).unwrap();
                println!("下载成功 {} {}", url, dest_file);
            }
            Err(e) => {
                println!("下载读取图片错误 {} {} {}", url, dest_file, e)
            }
        },
        Err(e) => {
            println!("请求下载图片错误 {} {} {}", url, dest_file, e)
        }
    }
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_shell::init())
        .invoke_handler(tauri::generate_handler![export_data])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
